/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @file  EthBuff.c
 * @brief Semidrive. AUTOSAR 4.3.1 MCAL Eth plugins.
 */
#ifdef __cplusplus
extern "C" {
#endif

#include "Eth.h"
#include "EthBuff.h"

#define  BYTE_BITS  (8U)

#ifndef  CTRL1_RX_BUFF_COUNT
#define  CTRL1_RX_BUFF_COUNT 0U
#endif
#ifndef  CTRL1_TX_BUFF_COUNT
#define  CTRL1_TX_BUFF_COUNT 0U
#endif
#ifndef  CTRL1_RX_BUFF_SIZE
#define  CTRL1_RX_BUFF_SIZE  0U
#endif
#ifndef  CTRL1_TX_BUFF_SIZE
#define  CTRL1_TX_BUFF_SIZE  0U
#endif

/* get max tx buff cnt */
#if CTRL0_TX_BUFF_COUNT > CTRL1_TX_BUFF_COUNT
#define CTRL_TX_BUFF_MAX CTRL0_TX_BUFF_COUNT
#else
#define CTRL_TX_BUFF_MAX CTRL1_TX_BUFF_COUNT
#endif
/* get max rx buff cnt */
#if CTRL0_RX_BUFF_COUNT > CTRL1_RX_BUFF_COUNT
#define CTRL_RX_BUFF_MAX CTRL0_RX_BUFF_COUNT
#else
#define CTRL_RX_BUFF_MAX CTRL1_RX_BUFF_COUNT
#endif
/* get max rx buff cnt */
#if CTRL_RX_BUFF_MAX > CTRL_TX_BUFF_MAX
#define CTRL_BUFF_MAX CTRL_RX_BUFF_MAX
#else
#define CTRL_BUFF_MAX CTRL_TX_BUFF_MAX
#endif
/* Make sure the structure size is not less than 32 bytes  */
#if ((CTRL_BUFF_MAX/BYTE_BITS) < 16U)
#define  FIFO_SUM_CNT_MAX   16U
#else
#define  FIFO_SUM_CNT_MAX   (CTRL_BUFF_MAX/BYTE_BITS)
#endif

typedef struct {
    uint8  membuf_state;
    uint8  membuf_bits[DIR_MAX][FIFO_SUM_CNT_MAX];
} __attribute__((aligned(CACHE_LINE))) MemBufM_t ;

typedef struct{
    uint16  down_start_index;
    uint16  bufflocalidx;
} search_params_t;

#define ETH_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Eth_MemMap.h"

static MemBufM_t MemBufM[ETH_MAXCTRLS_SUPPORTED];

#define ETH_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Eth_MemMap.h"

#if (ETH_NO_CACHEABLE_NEEDED == STD_ON)
#define ETH_START_SEC_VAR_NO_INIT_NO_CACHE_UNSPECIFIED
#else
#define ETH_START_SEC_VAR_NO_INIT_UNSPECIFIED
#endif
#include "Eth_MemMap.h"
/*PRQA S 1751 10*/
VAR_ALIGN(uint8 membuf0[CTRL0_TX_BUFF_SIZE + CTRL0_RX_BUFF_SIZE], \
          CACHE_LINE);

#if (ETH_MAXCTRLS_SUPPORTED == 2)
VAR_ALIGN(uint8 membuf1[CTRL1_TX_BUFF_SIZE + CTRL1_RX_BUFF_SIZE], \
          CACHE_LINE);
#endif

#if (ETH_NO_CACHEABLE_NEEDED == STD_ON)
#define ETH_STOP_SEC_VAR_NO_INIT_NO_CACHE_UNSPECIFIED
#else
#define ETH_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#endif
#include "Eth_MemMap.h"

#define ETH_START_SEC_CONST_UNSPECIFIED
#include "Eth_MemMap.h"

static uint8 *const membufp[ETH_MAXCTRLS_SUPPORTED] = \
{
    &membuf0[0]
#if (ETH_MAXCTRLS_SUPPORTED == 2)
    , &membuf1[0]
#endif
};

#define ETH_STOP_SEC_CONST_UNSPECIFIED
#include "Eth_MemMap.h"

#define ETH_START_SEC_CODE_FAST
#include "Eth_MemMap.h"

/**
 * @brief Retrieves the number of buffers available for the specified Ethernet controller and direction.
 *
 * This function returns the number of buffers available for either receive (RX) or transmit (TX)
 * operations on the specified Ethernet controller. The number of buffers is determined based on the
 * controller index (CtrlIdx) and whether the request is for receive (rx = true) or transmit (rx = false)
 * buffers.
 *
 * @param CtrlIdx The index or identifier of the Ethernet controller for which to retrieve the buffer count.
 * @param rx A boolean indicating whether to retrieve the receive (true) or transmit (false) buffer count.
 *
 * @return The number of buffers available for the specified controller and direction.
 *
 * @note The function assumes that the buffer counts for each controller and direction (RX/TX) are
 *       predefined and accessible through macros or global variables (e.g., CTRL0_RX_BUFF_COUNT,
 *       CTRL0_TX_BUFF_COUNT, CTRL1_RX_BUFF_COUNT, CTRL1_TX_BUFF_COUNT). These buffer counts should
 *       represent the maximum number of buffers available for the respective controller and direction.
 */
// Function to get the buffer count for a given controller index and receive/transmit flag
uint32 EthGetBufferCount(uint8 CtrlIdx, boolean rx)
{
    // Variable to store the buffer count
    uint32 buf_cnt;

    // Check if the controller index is 0
    if (0u == CtrlIdx) {
        // If the receive flag is true, set the buffer count to the receive buffer count for controller 0
        if (rx) {
            buf_cnt = CTRL0_RX_BUFF_COUNT;
        // Otherwise, set the buffer count to the transmit buffer count for controller 0
        } else {
            buf_cnt = CTRL0_TX_BUFF_COUNT;
        }
    // Otherwise, the controller index is 1
    } else {
        // If the receive flag is true, set the buffer count to the receive buffer count for controller 1
        if (rx) {
            buf_cnt = CTRL1_RX_BUFF_COUNT;
        // Otherwise, set the buffer count to the transmit buffer count for controller 1
        } else {
            buf_cnt = CTRL1_TX_BUFF_COUNT;
        }
    }

    // Return the buffer count
    return buf_cnt;
}
/**
 * @brief Calculates the size of a buffer in bytes for the specified Ethernet controller and direction.
 *
 * This inline function calculates and returns the size of a buffer in bytes for either receive (RX)
 * or transmit (TX) operations on the specified Ethernet controller. The buffer size is determined
 * based on the controller index (CtrlIdx) and whether the request is for receive (rx = true) or
 * transmit (rx = false) buffers.
 *
 * @param CtrlIdx The index or identifier of the Ethernet controller for which to calculate the buffer size.
 * @param rx A boolean indicating whether to calculate the receive (true) or transmit (false) buffer size.
 *
 * @return The size of a buffer in bytes for the specified controller and direction.
 *
 * @note This function is marked as `static inline`, which means it can only be used within the file
 *       in which it is defined and is intended for the compiler to expand the function call inline
 *       at the point of invocation, potentially improving performance by reducing the overhead of
 *       function calls.
 *
 * @note The function assumes that the buffer sizes for each controller and direction (RX/TX) are
 *       predefined and accessible through macros or global variables (e.g., CTRL0_RX_BUFF_SIZE,
 *       CTRL0_TX_BUFF_SIZE, CTRL1_RX_BUFF_SIZE, CTRL1_TX_BUFF_SIZE). These buffer sizes should
 *       represent the maximum number of bytes that can be stored in a single buffer for the respective
 *       controller and direction.
 */static inline uint32 cacul_buf_byte_cnt(uint8 CtrlIdx, boolean rx)
{
    // Declare a variable to store the byte count
    uint32 btyes_cnt;

    // If the control index is 0
    if (0u == CtrlIdx) {
        // If the transfer is in the receive direction
        if (rx) {
            // Set the byte count to the receive buffer size of control 0
            btyes_cnt = CTRL0_RX_BUFF_SIZE;
        } else {
            // Otherwise, set the byte count to the transmit buffer size of control 0
            btyes_cnt = CTRL0_TX_BUFF_SIZE;
        }
    } else {
        // If the transfer is in the receive direction
        if (rx) {
            // Set the byte count to the receive buffer size of control 1
            btyes_cnt = CTRL1_RX_BUFF_SIZE;
        } else {
            // Otherwise, set the byte count to the transmit buffer size of control 1
            btyes_cnt = CTRL1_TX_BUFF_SIZE;
        }
    }

    // Return the byte count
    return btyes_cnt;
}

#if (defined(DEBUG_ENABLE) && defined(DEBUG_BUFF))
/**
 * @brief Displays the status of buffers for the specified Ethernet controller and direction.
 *
 * This function prints the current status of buffers for either receive (RX) or transmit (TX)
 * operations on the specified Ethernet controller. It first prints the total number of buffers
 * (assuming the `EthGetBufferCount` function is intended to return this, despite the naming which
 * might suggest a count of buffers in use). Then, it iterates through the bit array representing
 * the status of individual buffers and prints each bit, where a set bit represents a buffer that
 * is in use or has some specific status (depending on the implementation details).
 *
 * @param CtrlIdx The index or identifier of the Ethernet controller for which to display the status.
 * @param rx A boolean indicating whether to display the receive (true) or transmit (false) buffer status.
 *
 * @note This function assumes that the `MemBufM_t` type and the `MemBufM` array are defined and accessible,
 *       and that they contain information about the buffers for each controller and direction.
 *
 * @note The `EthGetBufferCount` function is called with the `TRUE` macro/constant as the second argument,
 *       which suggests that it might be intended to return the total number of buffers available, but
 *       the naming and context suggest it might actually return the number of buffers in use or some
 *       other status-related count. This discrepancy should be addressed for clarity and consistency.
 *
 * @note The function uses the `DBG` macro/function for printing debug information. It's assumed that
 *       `DBG` is defined and functional, and that it takes a format string and optional arguments.
 *
 * @note The function iterates through the `FIFO_SUM_CNT_MAX` number of bits in the `membuf_bits` array,
 *       which suggests that there's a fixed limit on the number of buffers that can be tracked for each
 *       controller and direction. This limit should be defined and documented accordingly.
 */
static void show_status(uint8 CtrlIdx, boolean rx)
{
    MemBufM_t *BufM = &MemBufM[CtrlIdx];
    uint32 type = rx ? DIR_RX : DIR_TX;
    uint32 bits_sum = EthGetBufferCount(CtrlIdx, TRUE);
    DBG("sunbufitcnt %d\n", bits_sum);

    for (int de = 0; de < FIFO_SUM_CNT_MAX; de++) {
        DBG("%02x ", BufM->membuf_bits[type][de]);
    }

    DBG("\n");
}
#endif
/**
 * @brief Calculates the total number of bytes available in buffers for a specified FIFO range on an Ethernet controller.
 *
 * This inline function calculates and returns the total number of bytes that can be stored in buffers
 * for a specified range of FIFOs (First-In, First-Out buffers) on an Ethernet controller. The calculation
 * is based on the controller index (CtrlIdx), the number of FIFOs to consider (fifoNumber), and whether
 * the request is for receive (RX) or transmit (TX) FIFOs.
 *
 * @param CtrlIdx The index or identifier of the Ethernet controller for which to calculate the buffer byte limit.
 * @param fifoNumber The number of FIFOs to consider in the calculation.
 * @param rx A boolean indicating whether to calculate the receive (true) or transmit (false) FIFO buffer byte limit.
 *
 * @return The total number of bytes available in buffers for the specified FIFO range on the controller.
 *
 * @note This function is marked as `static inline`, which means it can only be used within the file
 *       in which it is defined and is intended for the compiler to expand the function call inline
 *       at the point of invocation, potentially improving performance by reducing the overhead of
 *       function calls.
 *
 * @note The function assumes that the `ETH_CFG_CTRL_PARM_PTR` macro or function is defined and returns
 *       a pointer to the configuration structure for the specified Ethernet controller index.
 *
 * @note The configuration structure (`Eth_CntrlConfigType`) is assumed to contain pointers to arrays
 *       of `Eth_CtrlConfigFifoType` structures, which define the configuration of ingress (receive)
 *       and egress (transmit) FIFOs. These structures are expected to have `FifoBufTotal` and `FifoBufLenByte`
 *       members that represent the total number of buffers and the size of each buffer in bytes, respectively.
 *
 * @warning The caller must ensure that the `fifoNumber` parameter does not exceed the actual number of
 *          FIFOs configured for the specified controller and direction (RX/TX), as accessing out-of-bounds
 *          elements of the `FifoParam` array could lead to undefined behavior.
 */
static inline uint32 cacul_buf_byte_cnt_limit(uint8 CtrlIdx, uint16 fifoNumber, boolean rx)
{
    uint32 buf_cnt = 0;
    const Eth_CntrlConfigType *cfg = ETH_CFG_CTRL_PARM_PTR(CtrlIdx);
    const Eth_CtrlConfigFifoType *FifoParam;

    if (rx) {
        FifoParam =  cfg->IngressFifoConfig;
    } else {
        FifoParam =  cfg->EgressFifoConfig;
    }

    for (uint16 loop = 0; loop < fifoNumber; loop++) {
        buf_cnt += FifoParam[loop].FifoBufTotal * FifoParam[loop].FifoBufLenByte;
    }

    return buf_cnt;
}
/**
 * @brief Checks if a free buffer is available in a specified FIFO of an Ethernet controller.
 *
 * This function checks if there is a free buffer available in the specified FIFO of an Ethernet controller.
 * It iterates through the bit array representing the status of buffers for the controller and direction
 * (RX/TX), starting from the beginning of the FIFO range up to the specified FIFO index (FifiIdx), and
 * then searches within the specified FIFO for a free buffer. If a free buffer is found, it optionally
 * locks the buffer by clearing the corresponding bit in the bit array.
 *
 * @param CtrlIdx The index or identifier of the Ethernet controller.
 * @param fifoarray A pointer to an array of `Eth_CtrlConfigFifoType` structures defining the configuration
 *                  of FIFOs for the controller.
 * @param FifiIdx The index of the FIFO within the `fifoarray` to search for a free buffer.
 * @param rx A boolean indicating whether to search for a free buffer in the receive (true) or transmit (false)
 *           FIFOs.
 * @param lock A boolean indicating whether to lock the found free buffer by clearing the corresponding bit
 *             in the bit array.
 *
 * @return The index of the found free buffer within the specified FIFO, or `ILLEGAL_BUFF_TYPE_IDX` if no
 *         free buffer is available.
 *
 * @note The function assumes that the `MemBufM_t` type and the `MemBufM` array are defined and accessible,
 *       and that they contain information about the buffers for each controller and direction.
 *
 * @note The function assumes that the `BYTE_BITS` macro/constant is defined and represents the number of
 *       bits in a byte (typically 8).
 *
 * @note The function uses `SchM_Enter_Eth_ETH_EXCLUSIVE_AREA_03` and `SchM_Exit_Eth_ETH_EXCLUSIVE_AREA_03`
 *       functions (or macros) to enter and exit a critical section, ensuring that the bit array is accessed
 *       in a thread-safe manner.
 *
 * @warning The caller must ensure that the `fifoarray` parameter is not NULL and that `FifiIdx` is a valid
 *          index within the range of FIFOs defined by the `fifoarray`. Accessing an invalid `fifoarray` or
 *          `FifiIdx` could lead to undefined behavior.
 */
static uint32 fifo_have_free(uint8 CtrlIdx, const Eth_CtrlConfigFifoType *fifoarray\
                             , uint32 FifiIdx, boolean rx,boolean lock)
{
    uint32 part_bits;
    MemBufM_t *BufM = &MemBufM[CtrlIdx];
    uint32 loop, whole_byte = 0;
    uint32 bits_cnt = 0;
    uint32 type = rx ? DIR_RX : DIR_TX;

    if (!fifoarray) {
        return ILLEGAL_BUFF_TYPE_IDX;
    }

    for (loop = 0; loop < FifiIdx; loop++) {
        bits_cnt += fifoarray[loop].FifoBufTotal;
    }

    /* The first fifo may be negative here*/
    if (bits_cnt) {
        whole_byte = ((bits_cnt - 1) / BYTE_BITS);
    }

    part_bits = bits_cnt % BYTE_BITS;

    /*
        If part_bits is 0 and FifiIdx is not 0 ,
        the byte idx points to the bit position of the previous buf.
    */
    if (!part_bits && bits_cnt) {
        whole_byte++;
    }

    for (loop = 0; loop < fifoarray[FifiIdx].FifoBufTotal; loop++) {
        /*
           When the sum of the previous buf cnt is aligned,
           bytes idx has already been +1 at line 155. so Exclude loop==0
           and add 1 for every 8bits.
        */
        if (loop && (!((loop + part_bits) % BYTE_BITS))) {
            whole_byte++;
        }
        SchM_Enter_Eth_ETH_EXCLUSIVE_AREA_03();
        if (BufM->membuf_bits[type][whole_byte] & \
            (uint8)(0x01 << ((part_bits + loop) % BYTE_BITS))) {
            if(lock){
                BufM->membuf_bits[type][whole_byte] \
                &= (uint8)(~((0x01 << ((part_bits + loop) % BYTE_BITS))));
            }
            SchM_Exit_Eth_ETH_EXCLUSIVE_AREA_03();
            return loop;
        }
        SchM_Exit_Eth_ETH_EXCLUSIVE_AREA_03();
    }

    return ILLEGAL_BUFF_TYPE_IDX;
}
/**
 *
 * @description:
 * @param {uint8} CtrlIdx
 * @param {uint16} len
 * @param {boolean} rx
 * @return {*}
 */
static sint16 search_up(uint8 CtrlIdx, const Eth_CtrlConfigFifoType *fifoarray,
                        uint16 fifocnt, uint16 *len, boolean rx,
                        search_params_t *ret_params)
{
    uint32 bufflocalidx;
    /*
        In Eth_PBCfg.c the fifo is Sorted by size,so the larger the
        index, the larger the buf size
    */
    for (uint32 idx = 0; idx < fifocnt; idx++) {
        if (fifoarray[idx].FifoBufLenByte >= *len) {
            if (ret_params->down_start_index == ILLEGAL_BUFF_TYPE_IDX) {
                /* Save the previous starting fifo type idx of
                    the upward search as the upper limit of the downward search
                */
                ret_params->down_start_index = idx;
            }
            bufflocalidx = fifo_have_free(CtrlIdx, fifoarray, idx, rx,TRUE);
            if (bufflocalidx != ILLEGAL_BUFF_TYPE_IDX) {
                *len = fifoarray[idx].FifoBufLenByte;
                ret_params->bufflocalidx = bufflocalidx;
                return idx;
            } else {
                continue;
            }
        }
    }

    /* search_up fail */
    return -1;
}
/**
 * @brief Searches for a free buffer in FIFOs of an Ethernet controller, starting from a specified index and moving downwards.
 *
 * This function searches for a free buffer in the FIFOs of an Ethernet controller, starting from the specified
 * FIFO index (fifoidx) and moving towards smaller FIFO indexes (i.e., searching downwards). It iterates through
 * the FIFOs in reverse order, comparing the size of each FIFO's buffers with a given length (*len), and attempts
 * to find a free buffer in the first FIFO whose buffers are smaller than or equal to the given length.
 *
 * @param CtrlIdx The index or identifier of the Ethernet controller.
 * @param fifoarray A pointer to an array of `Eth_CtrlConfigFifoType` structures defining the configuration
 *                  of FIFOs for the controller.
 * @param fifoidx The starting index of the FIFO range to search within.
 * @param len A pointer to a variable containing the desired length of the buffer to search for. If a free
 *            buffer is found, this variable will be updated with the actual buffer length.
 * @param rx A boolean indicating whether to search for a free buffer in the receive (true) or transmit (false)
 *           FIFOs.
 *
 * @return The index of the FIFO in which a free buffer was found, or -1 if no free buffer was available.
 *
 * @note The function assumes that the FIFOs in the `fifoarray` are sorted by size in descending order,
 *       such that larger FIFO indexes correspond to larger buffer sizes.
 *
 * @note The function uses the `fifo_have_free` function to check if a free buffer is available in a given
 *       FIFO and, if so, returns the index of that FIFO.
 *
 * @note The function updates the value pointed to by the `len` parameter to the actual buffer length of
 *       the found free buffer.
 *
 * @warning The caller must ensure that the `fifoarray` parameter is not NULL and that `fifoidx` is a valid
 *          index within the range of FIFOs defined by the `fifoarray`. Accessing an invalid `fifoarray` or
 *          `fifoidx` could lead to undefined behavior.
 */
static sint16 search_down(uint8 CtrlIdx, const Eth_CtrlConfigFifoType *fifoarray, \
                          uint16 fifoidx, uint16 *len, boolean rx)
{
    uint32 fifolocalidx;
    /*
        In Eth_PBCfg.c the fifo is Sorted by size,so the larger the
        index, the larger the buf size
    */
    for (sint16 Idx = fifoidx; Idx >= 0; Idx--) {
        if (fifoarray[Idx].FifoBufLenByte < *len) {
            fifolocalidx = fifo_have_free(CtrlIdx, fifoarray, (uint32)Idx, rx,FALSE);
            if (ILLEGAL_BUFF_TYPE_IDX != fifolocalidx) {
                *len = fifoarray[Idx].FifoBufLenByte;
                return Idx;
            }
        }
    }

    /* no buf available */
    *len = 0;
    return -1;
}
/**
 * @brief Checks if a buffer in the Ethernet controller's memory is locked.
 *
 * This function checks the status of a specific buffer in the memory of an Ethernet controller to determine
 * if it is currently locked (i.e., in use) or free. The check is performed by examining a bit array that
 * represents the status of buffers for the specified controller and direction (RX/TX).
 *
 * @param CtrlIdx The index or identifier of the Ethernet controller.
 * @param bufidx The index of the buffer to check.
 * @param rx A boolean indicating whether to check the receive (true) or transmit (false) buffers.
 *
 * @return A value indicating the status of the buffer:
 *         - 0: The buffer is free (not locked).
 *         - 1: The buffer is locked (in use).
 *
 * @note The function assumes that the `MemBufM_t` type and the `MemBufM` array are defined and accessible,
 *       and that they contain information about the buffers for each controller and direction.
 *
 * @note The function assumes that the `BYTE_BITS` macro/constant is defined and represents the number of
 *       bits in a byte (typically 8).
 *
 * @warning The caller must ensure that the `bufidx` parameter is a valid index within the range of buffers
 *          managed by the specified controller and direction. Accessing an invalid `bufidx` could lead to
 *          undefined behavior.
 */
static uint32 is_locked_bufmem(uint8 CtrlIdx, uint32 bufidx, boolean rx)
{

    uint32 dir = rx ? DIR_RX : DIR_TX;
    MemBufM_t *BufM = &MemBufM[CtrlIdx];

    if ((BufM->membuf_bits[dir][bufidx / BYTE_BITS] &\
          (uint8)((0x01 << (bufidx % BYTE_BITS))))) {
        /* free */
        return 0;
    }

    /* not free */
    return 1;
}
/**
 * @description:
 * @param {uint8} CtrlIdx
 * @param {sint16} fifoidx
 * @param {uint16} BufIndex
 * @param {boolean} rx
 * @return {*}
 */
static  uint8 *get_bufptr(uint8 CtrlIdx, uint16 fifoidx, uint16 BufIndex, boolean rx)
{
    uint8 *membufptr;
    uint8 offset_ptr;
    uint32 btye_offset = 0;
    const Eth_CntrlConfigType *cfg = ETH_CFG_CTRL_PARM_PTR(CtrlIdx);
    const Eth_CtrlConfigFifoType *FifoParam;

    /* The RX part is in the second half */
    if (rx) {
        /*
        Note:
            mem laout: tx buf[....]---rx buf[....]
            So calculating the starting address of receiving buf
            needs to increase the size of the address space for sending buf.
        */
        btye_offset =  cacul_buf_byte_cnt(CtrlIdx, FALSE);
        FifoParam =  cfg->IngressFifoConfig;
        offset_ptr = 0;
    } else {
        FifoParam =  cfg->EgressFifoConfig;
        offset_ptr = MAC_HEADER_LEN;
    }

    btye_offset +=  cacul_buf_byte_cnt_limit(CtrlIdx, fifoidx, rx);
    btye_offset += BufIndex * FifoParam[fifoidx].FifoBufLenByte;
    membufptr = (uint8 *)membufp[CtrlIdx ];
    return &membufptr[btye_offset + offset_ptr];
}
/**
 * @brief Calculates the global buffer index from a FIFO-specific buffer index.
 *
 * This function computes the global buffer index corresponding to a given
 * FIFO-specific buffer index and FIFO identifier. It iterates through the array of
 * FIFO configuration structures (`fifoarray`), accumulating the total number of
 * buffers in all FIFOs up to (but not including) the specified FIFO identifier
 * (`fifoidx`). The accumulated byte offset is then added to the FIFO-specific buffer
 * index (`BufIndex`) to obtain the global buffer index.
 *
 * @param CtrlIdx The index of the Ethernet controller associated with the FIFOs.
 * @param fifoarray A pointer to an array of `Eth_CtrlConfigFifoType` structures,
 *                  each containing configuration information for a FIFO.
 * @param fifoidx The identifier of the FIFO for which to calculate the global
 *                buffer index.
 * @param BufIndex The FIFO-specific buffer index.
 *
 * @return uint32 The global buffer index corresponding to the specified
 *                FIFO-specific buffer index and FIFO identifier.
 *
 * @note This function assumes that the FIFO configuration structures in `fifoarray`
 *       are ordered by FIFO identifier and that the `FifoBufTotal` field in each
 *       structure contains the total number of buffers in the corresponding FIFO.
 *
 *       The function does not perform any error checking on the input parameters
 *       (e.g., to ensure that `fifoidx` is within the valid range for the given
 *       controller and `fifoarray`). Therefore, it is the caller's responsibility
 *       to ensure that the input parameters are valid.
 */
static uint32 get_bufidx(uint8 CtrlIdx, const Eth_CtrlConfigFifoType *fifoarray, \
                         uint16 fifoidx, uint16 BufIndex)
{

    uint16 btye_offset = 0;
    /*
        Index is monotonic according to the type of FIFO
    */
    for (uint16 Idx = 0; Idx < fifoidx; Idx++) {
        btye_offset += fifoarray[Idx].FifoBufTotal;
    }

    return (uint32)(btye_offset + BufIndex);
}
/**
 * @description:get buf address by buff idx and type
 * @param {uint8} CtrlIdx
 * @param {uint16} BufIndex
 * @param {boolean} rx
 * @return {*}
 */
static uint8 *get_bufptrby_idx(uint8 CtrlIdx, uint32 BufIndex, boolean rx)
{
    uint8 *membufptr;
    uint16 FifoNumber;
    uint16 Idx;
    uint32 btye_offset = 0;
    const Eth_CntrlConfigType *cfg = ETH_CFG_CTRL_PARM_PTR(CtrlIdx);
    const Eth_CtrlConfigFifoType *FifoParam;

    /* The RX part is in the second half */
    if (rx) {
        /*
        Note:
            mem laout: tx buf[....]---rx buf[....]
            So calculating the starting address of receiving buf
            needs to increase the size of the address space for sending buf.
        */
        btye_offset =  cacul_buf_byte_cnt(CtrlIdx, FALSE);
        FifoNumber = cfg->IngressFifoNumber;
        FifoParam =  cfg->IngressFifoConfig;
    } else {
        FifoNumber = cfg->EgressFifoNumber;
        FifoParam =  cfg->EgressFifoConfig;
    }



    for (Idx = 0; Idx < FifoNumber; Idx++) {
        if (BufIndex < FifoParam[Idx].FifoBufTotal) {
            break;
        }

        BufIndex -= FifoParam[Idx].FifoBufTotal;
    }

    btye_offset += cacul_buf_byte_cnt_limit(CtrlIdx, Idx, rx);
    btye_offset += FifoParam[Idx].FifoBufLenByte * BufIndex;
    membufptr = (uint8 *)membufp[CtrlIdx];
    return &membufptr[btye_offset];
}

#define ETH_STOP_SEC_CODE_FAST
#include "Eth_MemMap.h"

#define ETH_START_SEC_CODE
#include "Eth_MemMap.h"
/**
 * @brief Initializes the buffer memory status arrays for an Ethernet controller.
 *
 * This function initializes the bit arrays that represent the status of buffers for an Ethernet controller,
 * specifically for receive (RX) and transmit (TX) operations. It sets all bits in the RX and TX bit arrays
 * to indicate that buffers are initially free, based on the total number of buffers available for each direction
 * as returned by the `EthGetBufferCount` function.
 *
 * @param CtrlIdx The index or identifier of the Ethernet controller to initialize.
 *
 * @note The function assumes that the `MemBufM_t` type and the `MemBufM` array are defined and accessible,
 *       and that they contain information about the buffers for each controller and direction.
 *
 * @note The function assumes that the `BYTE_BITS` macro/constant is defined and represents the number of
 *       bits in a byte (typically 8).
 *
 * @note The function calls the `EthGetBufferCount` function twice, once for RX buffers and once for TX buffers,
 *       to retrieve the total number of buffers available for each direction.
 *
 * @note After initialization, the `membuf_state` member of the `MemBufM_t` structure for the specified controller
 *       is set to 1, indicating that the buffer memory status arrays have been initialized.
 */
void EthBuffInit(uint8 CtrlIdx)
{
    uint8 byte;
    uint32 bits_sum = EthGetBufferCount(CtrlIdx, TRUE);
    byte = 0;

    if (CtrlIdx < ETH_MAXCTRLS_SUPPORTED)
    {
        MemBufM_t *BufM = &MemBufM[CtrlIdx];
        /*PRQA S 2877 5*/
        while (bits_sum >= BYTE_BITS) {
            BufM->membuf_bits[DIR_RX][byte++] = 0xFF;
            bits_sum -= BYTE_BITS;
        }

        BufM->membuf_bits[DIR_RX][byte] = 0;
        BufM->membuf_bits[DIR_RX][byte] |= (uint8)((0x1u << (bits_sum % BYTE_BITS)) - 1u);
        bits_sum = EthGetBufferCount(CtrlIdx, FALSE);

        byte = 0;

        while (bits_sum >= BYTE_BITS) {
            BufM->membuf_bits[DIR_TX][byte++] = 0xFF;
            bits_sum -= BYTE_BITS;
        }

        BufM->membuf_bits[DIR_TX][byte] = 0;
        BufM->membuf_bits[DIR_TX][byte] |= (uint8)((0x1u << (bits_sum % BYTE_BITS)) - 1u);
        BufM->membuf_state  = 1;
    }
}
/**
 * @description:deinit the membuf alloctor
 * @param {uint8} CtrlIdx
 * @return {*}
 */
void EthBuffDeInit(uint8 CtrlIdx)
{
    MemBufM_t *BufM = &MemBufM[CtrlIdx];
    BufM->membuf_state  = 0;
}
#define ETH_STOP_SEC_CODE
#include "Eth_MemMap.h"

#define ETH_START_SEC_CODE_FAST
#include "Eth_MemMap.h"

/**
 * @brief Allocates a buffer from an Ethernet controller's memory based on the specified criteria.
 *
 * This function attempts to allocate a buffer from the memory of an Ethernet controller, either for receive
 * (RX) or transmit (TX) operations. It searches through the FIFOs configured for the controller, starting
 * from the largest FIFOs and moving towards smaller ones, to find a buffer that meets or exceeds the
 * specified length requirement. If no such buffer is available, it searches downwards from a specified
 * starting point to find a smaller buffer, if possible.
 *
 * @param CtrlIdx The index or identifier of the Ethernet controller from which to allocate a buffer.
 * @param Len A pointer to a variable containing the desired length of the buffer. If a buffer is allocated,
 *            this variable will be updated with the actual length of the allocated buffer.
 * @param Bufptr A pointer to a pointer that will be updated to point to the allocated buffer, if successful.
 * @param BufIdxptr A pointer to a variable that will be updated with the index of the allocated buffer,
 *                  if successful.
 * @param rx A boolean indicating whether to allocate a buffer for receive (true) or transmit (false) operations.
 *
 * @return An integer indicating the result of the allocation attempt:
 *         - 0: A buffer of the desired length or greater was successfully allocated.
 *         - -1: No buffer was available.
 *         - -2: Only smaller buffers were available, but none of the desired length or greater.
 *
 * @note The function assumes that the Ethernet controller's configuration (including FIFO configurations)
 *       has been initialized and is accessible through the `ETH_CFG_CTRL_PARM_PTR` macro.
 *
 * @note The function uses the `search_up` and `search_down` functions to search for a suitable buffer.
 *
 * @note The function updates the `Len` parameter to reflect the actual length of the allocated buffer,
 *       if successful.
 *
 * @note The function uses the `get_bufidx` and `get_bufptr` functions (or similar mechanisms) to retrieve
 *       the index and pointer of the allocated buffer, respectively.
 *
 * @warning The caller must ensure that the `Bufptr` and `BufIdxptr` parameters are not NULL, and that
 *          they are valid pointers to writable memory.
 *
 * @warning The function may modify the `Len` parameter if a smaller buffer is allocated than the one
 *          requested.
 */
sint32 EthBuffAlloc(uint8 CtrlIdx, uint16 *Len, uint8 **Bufptr, \
                    Eth_BufIdxType *BufIdxptr, boolean rx)
{

    uint16 FifoNumber;
    sint16 FifoIndex;
    search_params_t ret_params;
    const Eth_CntrlConfigType *cfg = ETH_CFG_CTRL_PARM_PTR(CtrlIdx);
    const Eth_CtrlConfigFifoType *FifoParam;
    MemBufM_t *BufM = &MemBufM[CtrlIdx];
    *Bufptr = NULL_PTR;

    /*
        alloctor is not inited .
    */
    if (NULL_PTR == cfg|| 0 == BufM->membuf_state) {
        return -1;
    }

    if (rx) {
        FifoNumber = cfg->IngressFifoNumber;
        FifoParam =  cfg->IngressFifoConfig;
    } else {
        FifoNumber = cfg->EgressFifoNumber;
        FifoParam =  cfg->EgressFifoConfig;
    }

    /*
        If you need a buf of x bytes, the allocator can allocate a buf that is greater
        than or equal to x, but if there is no buf that is greater than or equal to,
        the allocator needs to return the size of the available buf that is less than x
    */

    ret_params.down_start_index = ILLEGAL_BUFF_TYPE_IDX;
    FifoIndex = search_up(CtrlIdx, FifoParam, FifoNumber, Len, rx, &ret_params);

    if (FifoIndex >= 0) {
        *BufIdxptr = get_bufidx(CtrlIdx, FifoParam, (uint16)FifoIndex, ret_params.bufflocalidx);
        *Bufptr = get_bufptr(CtrlIdx, (uint16)FifoIndex, ret_params.bufflocalidx, rx);
#if (defined(DEBUG_ENABLE) && defined(DEBUG_BUFF))
        show_status(CtrlIdx, rx);
#endif
        return 0;
    } else {
        /* search_down has modify the Len if have free buf */
        if (ret_params.down_start_index != ILLEGAL_BUFF_TYPE_IDX) {
            FifoNumber = (uint16)ret_params.down_start_index;
        }
        if(FifoNumber == 0u){

            /* ret_params.down_start_index = 0 means that no buf available */
            return -1;
        }else{

            FifoIndex = search_down(CtrlIdx, FifoParam, FifoNumber - 1u, Len, rx);

            if (FifoIndex >= 0) {
                /* Only smaller bufs are available */
                return -2;
            } else {
                /*  no buf available */
                return -1;
            }
        }
    }
}
/**
 * @brief Frees a buffer in an Ethernet controller's memory.
 *
 * This function marks a buffer in the memory of an Ethernet controller as free, either for receive (RX)
 * or transmit (TX) operations. It updates the corresponding bit in the buffer status array to indicate
 * that the buffer is now available for reallocation.
 *
 * @param CtrlIdx The index or identifier of the Ethernet controller from which to free the buffer.
 * @param BufIdx The index of the buffer to free.
 * @param rx A boolean indicating whether the buffer is for receive (true) or transmit (false) operations.
 *
 * @note The function assumes that the `MemBufM_t` type and the `MemBufM` array are defined and accessible,
 *       and that they contain information about the buffers for each controller and direction.
 *
 * @note The function assumes that the `BYTE_BITS` macro/constant is defined and represents the number of
 *       bits in a byte (typically 8).
 *
 * @note The function uses the `EthGetBufferCount` function to ensure that the provided `BufIdx` is within
 *       the valid range of buffers for the specified controller and direction.
 *
 * @note The function enters and exits a critical section (using `SchM_Enter_Eth_ETH_EXCLUSIVE_AREA_03` and
 *       `SchM_Exit_Eth_ETH_EXCLUSIVE_AREA_03` functions or similar mechanisms) to ensure thread safety
 *       when updating the buffer status array.
 *
 * @warning The caller must ensure that the `BufIdx` parameter is a valid index within the range of buffers
 *          managed by the specified controller and direction. Accessing an invalid `BufIdx` could lead to
 *          undefined behavior.
 *
 * @warning The function does not perform any checks to validate the `membuf_state` value other than to
 *          ensure that it is not zero before attempting to free the buffer. If the allocator has not been
 *          initialized properly, this could lead to undefined behavior.
 */
void EthBuffFree(uint8 CtrlIdx, Eth_BufIdxType BufIdx, boolean rx)
{
    MemBufM_t *BufM = &MemBufM[CtrlIdx];
    uint32 dir = rx ? DIR_RX : DIR_TX;
    /*
        alloctor is not inited .
    */

    if (BufM->membuf_state && BufIdx < EthGetBufferCount(CtrlIdx, rx)) {
        SchM_Enter_Eth_ETH_EXCLUSIVE_AREA_03();
        BufM->membuf_bits[dir][BufIdx / BYTE_BITS] |=
            (uint8)(0x01 << (BufIdx % BYTE_BITS));
        SchM_Exit_Eth_ETH_EXCLUSIVE_AREA_03();
    }
#if (defined(DEBUG_ENABLE) && defined(DEBUG_BUFF))
    show_status(CtrlIdx, rx);
#endif
}
/**
 * @brief Retrieves the address of a buffer in an Ethernet controller's memory.
 *
 * This function returns the address of a buffer in the memory of an Ethernet controller, either for
 * receive (RX) or transmit (TX) operations. The address is retrieved based on the provided controller
 * index (`CtrlIdx`) and buffer index (`BufIdx`).
 *
 * @param CtrlIdx The index or identifier of the Ethernet controller.
 * @param BufIdx The index of the buffer for which to retrieve the address.
 * @param rx A boolean indicating whether the buffer is for receive (true) or transmit (false) operations.
 *
 * @return The address of the buffer, as a `uint32` value. If the buffer does not exist or the allocator
 *         has not been initialized properly, the function returns 0.
 *
 * @note The function assumes that the `MemBufM_t` type and the `MemBufM` array are defined and accessible,
 *       and that they contain information about the buffers for each controller and direction.
 *
 * @note The function uses the `EthGetBufferCount` function to ensure that the provided `BufIdx` is within
 *       the valid range of buffers for the specified controller and direction.
 *
 * @note The function relies on an implementation-specific function `get_bufptrby_idx` (or similar) to
 *       retrieve the buffer pointer based on the controller index, buffer index, and direction.
 *
 * @warning The caller must ensure that the `BufIdx` parameter is a valid index within the range of buffers
 *          managed by the specified controller and direction. Accessing an invalid `BufIdx` could lead to
 *          undefined behavior.
 *
 * @warning The function does not perform any checks to validate the `membuf_state` value other than to
 *          ensure that it is not zero before attempting to retrieve the buffer address. If the allocator
 *          has not been initialized properly, this could lead to undefined behavior.
 */
uint32 EthBuffAddr(uint8 CtrlIdx, Eth_BufIdxType BufIdx, boolean rx)
{
    /*
        alloctor is not inited .
    */
    MemBufM_t *BufM = &MemBufM[CtrlIdx];

    if (BufM->membuf_state && BufIdx < EthGetBufferCount(CtrlIdx, rx)) {
        return (uint32)get_bufptrby_idx(CtrlIdx, BufIdx, rx);
    }

    return 0;
}
/**
 * @description:
 * @param {uint8} CtrlIdx
 * @param {Eth_BufIdxType} BufIdx
 * @param {boolean} rx
 * @return {*}
 */
uint32 EthBuffIsAllocated(uint8 CtrlIdx, Eth_BufIdxType BufIdx, boolean rx)
{
    /*
        alloctor is not inited .
    */
    MemBufM_t *BufM = &MemBufM[CtrlIdx];

    if (BufM->membuf_state && BufIdx < EthGetBufferCount(CtrlIdx, rx)) {
        return is_locked_bufmem(CtrlIdx, BufIdx, rx);
    }
    return 0;
}
/**
 * @description:get buf address by buff idx and type
 * @param {uint8} CtrlIdx
 * @param {uint16} BufIndex
 * @param {boolean} rx
 * @return {*}
 */
uint32 EthBuffGetSizeByIdx(uint8 CtrlIdx, uint16 BufIndex, boolean rx)
{
    uint8 FifoNumber;
    uint16 Idx,tempBufCount=0;
    const Eth_CntrlConfigType *cfg = ETH_CFG_CTRL_PARM_PTR(CtrlIdx);
    const Eth_CtrlConfigFifoType *FifoParam;

    /* The RX part is in the second half */
    if (rx) {
        /*
        Note:
            mem laout: tx buf[....]---rx buf[....]
            So calculating the starting address of receiving buf
            needs to increase the size of the address space for sending buf.
        */
        FifoNumber = cfg->IngressFifoNumber;
        FifoParam =  cfg->IngressFifoConfig;
    } else {
        FifoNumber = cfg->EgressFifoNumber;
        FifoParam =  cfg->EgressFifoConfig;
    }

    for (Idx = 0; Idx < FifoNumber; Idx++) {
        tempBufCount += FifoParam[Idx].FifoBufTotal;
        if (BufIndex < tempBufCount) {
            break;
        }
    }

    return FifoParam[Idx].FifoBufLenByte;
}
/**
 * @brief Retrieves the index of a buffer based on its address.
 *
 * This function iterates through the list of buffers managed by the specified
 * Ethernet controller, searching for the buffer whose address range contains the
 * given buffer address. The search is performed separately for receive and transmit
 * buffers, depending on the value of the `is_rx` parameter.
 *
 * @param CtrlIdx The index of the Ethernet controller associated with the buffers.
 * @param buffaddr A pointer to the buffer for which to retrieve the index.
 * @param is_rx A boolean flag indicating whether to search for receive buffers
 *             (`true`) or transmit buffers (`false`).
 *
 * @return Eth_BufIdxType The index of the buffer that contains the given address, or
 *         `ILLEGAL_BUFF_IDX` if no such buffer is found.
 *
 * @note This function assumes that `EthGetBufferCount`, `get_bufptrby_idx`, and
 *       `EthBuffGetSizeByIdx` are helper functions that provide information about
 *       the buffers managed by the specified Ethernet controller. Specifically,
 *       `EthGetBufferCount` returns the number of buffers, `get_bufptrby_idx`
 *       returns the address of a buffer given its index, and `EthBuffGetSizeByIdx`
 *       returns the size of a buffer given its index.
 *
 *       The function compares the given buffer address (`buffaddr`) with the
 *       address range of each buffer in the list. If the address falls within the
 *       range of a buffer (i.e., it is greater than or equal to the buffer's start
 *       address and less than the buffer's end address), the function returns the
 *       index of that buffer. If no buffer is found that contains the given address,
 *       the function returns `ILLEGAL_BUFF_IDX`.
 */
static Eth_BufIdxType get_idx_of_buff(uint8 CtrlIdx, const Eth_DataType  *buffaddr, boolean is_rx)
{
    uint32 curr_buff_addr, BufIndex;

    for (BufIndex = 0; BufIndex < EthGetBufferCount(CtrlIdx, is_rx); BufIndex++) {
        curr_buff_addr = (uint32)get_bufptrby_idx(CtrlIdx, BufIndex, is_rx);

        if (curr_buff_addr <= (uint32)buffaddr  &&
            (curr_buff_addr + EthBuffGetSizeByIdx(CtrlIdx, (uint32)BufIndex, is_rx)) >
            (uint32)buffaddr ) {
            return BufIndex;
        }
    }

    return ILLEGAL_BUFF_IDX;
}

/**
 * @brief Converts a buffer address to a buffer index.
 *
 * This function takes a controller index, a buffer address, and a flag indicating
 * whether the buffer is for receive or transmit, and attempts to convert the buffer
 * address to a buffer index. The function first checks if the memory buffer manager
 * for the specified controller is initialized and ready to use. If so, it calls
 * `get_idx_of_buff` to perform the address-to-index conversion. If the memory buffer
 * manager is not initialized, or if `get_idx_of_buff` fails to find a valid index,
 * the function returns `ILLEGAL_BUFF_IDX`.
 *
 * @param CtrlIdx The index of the Ethernet controller associated with the buffer.
 * @param Bufaddr A pointer to the buffer for which to retrieve the index.
 * @param rx A boolean flag indicating whether the buffer is for receive (`true`) or
 *           transmit (`false`).
 *
 * @return Eth_BufIdxType The buffer index corresponding to the specified address, or
 *         `ILLEGAL_BUFF_IDX` if the conversion fails.
 *
 * @note This function assumes that `MemBufM` is a global or statically allocated
 *       array of `MemBufM_t` structures, one for each Ethernet controller. The
 *       `membuf_state` field in each `MemBufM_t` structure indicates whether the
 *       memory buffer manager for the corresponding controller is initialized.
 *
 *       The `get_idx_of_buff` function is expected to be a helper function that
 *       searches through the list of buffers managed by the specified controller
 *       and returns the index of the buffer with the matching address. The
 *       implementation of `get_idx_of_buff` is not shown here.
 */
Eth_BufIdxType EthBuffIdxFormAddr(uint8 CtrlIdx, const Eth_DataType *Bufaddr, boolean rx)
{
    /*
        alloctor is not inited .
    */
    MemBufM_t *BufM = &MemBufM[CtrlIdx];

    if (BufM->membuf_state) {
        return get_idx_of_buff(CtrlIdx, Bufaddr, rx);
    }
    return ILLEGAL_BUFF_IDX;
}
#define ETH_STOP_SEC_CODE_FAST
#include "Eth_MemMap.h"

#ifdef __cplusplus
}
#endif
